//ip代理池
package ippool

import (
	"BossSplider/pkg/splider"
	"errors"
	"fmt"
	"log"
	"sync"
	"sync/atomic"

	"github.com/PuerkitoBio/goquery"
)

var (
	Proxys      []*Proxy
	BaseUrl            = "http://www.xicidaili.com/wt/"
	maxIpNum    uint32 = 5
	proxyNum    uint32 = 0
	rountineNum sync.WaitGroup
)

type Proxy struct {
	IP      string
	Port    string
	Address string
	Type    string
}

//加载ip
func Load() {
	log.Println("加载ip中，请稍后...")

	var page uint32 = 1
	proxy_chan := make(chan *Proxy)

	//循环加载proxy
	go saveProxy(proxy_chan)

	for {
		log.Printf("加载第%d个ip列表", page)
		proxyList, err := getProxys(page)
		if err != nil {
			log.Println("加载错误!")
			return
		}

		proxyNum := len(proxyList)
		rountineNum.Add(proxyNum)
		for i := 0; i < proxyNum; i++ {
			go checkIp(proxyList[i], proxy_chan)
		}

		rountineNum.Wait()
		if getIpLen() >= maxIpNum {
			log.Println("加载完成")
			return
		} else {
			//加载下一页数据
			page++
		}
	}

}

//存储proxy，超过限制的ip个数，则返回
func saveProxy(pro chan *Proxy) {
	for {
		select {
		case proxy := <-pro:
			Proxys = append(Proxys, proxy)
			addIpLen() //当前ip池长度+1
			num := getIpLen()
			log.Printf("加载第%d个有效数据:%s", num, proxy.IP)
			if num >= maxIpNum {
				return
			}
		}
	}
}

//从数据源中获取1页ip数据
func getProxys(page uint32) (pool []*Proxy, err error) {
	body, status := splider.HttpGet(fmt.Sprintf("%s%d", BaseUrl, page), getIp())
	if status != 200 {
		return nil, errors.New(fmt.Sprintf("splider httpget error:%d", status))
	}

	doc, err := goquery.NewDocumentFromReader(body)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Downloader err:%s", err))
	}

	doc.Find("#ip_list tr").Each(func(i int, selection *goquery.Selection) {
		ip := selection.Find("td").Eq(1).Text()
		port := selection.Find("td").Eq(2).Text()
		address := selection.Find("td").Eq(3).Find("a").Text()
		url_type := selection.Find("td").Eq(5).Text()

		proxy := &Proxy{
			IP:      ip,
			Port:    port,
			Address: address,
			Type:    url_type,
		}

		if ip != "" {
			pool = append(pool, proxy)
		}
	})

	return pool, nil
}

//检查数据是否有效
func checkIp(proxy *Proxy, proxy_chan chan *Proxy) {
	if getIpLen() >= maxIpNum {
		return
	}
	_, status := splider.HttpGet("http://www.baidu.com", returnIp(proxy))
	if status == 200 {
		log.Printf("ip %s 有效", returnIp(proxy))
		proxy_chan <- proxy
	}
	log.Printf("ip %s 无效,%d", returnIp(proxy), status)
	rountineNum.Done()
}

//返回一个Ip字符串
func returnIp(proxy *Proxy) string {
	return proxy.Type + "://" + proxy.IP + ":" + proxy.Port
}

func getIpLen() uint32 {
	return atomic.LoadUint32(&proxyNum)
}

func addIpLen() error {
	atomic.AddUint32(&proxyNum, 1)

	return nil
}

//返回一个有效的ip,如果没有则返回local
func getIp() string {
	if getIpLen() > 0 {
		return returnIp(Proxys[0])
	} else {
		return "local"
	}

}
